/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef DEPENDENCY_UCOP_STORAGE_SQLSTORAGE_H_
#define DEPENDENCY_UCOP_STORAGE_SQLSTORAGE_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <cstdint>
#include <map>
#include <boost/unordered_map.hpp>
#include "Ucop/Data/Rel/Session.h"
#include "Ucop/DBC/DBCLoader.h"
using Ucop::DBC::FieldFormat;
using Ucop::Data::Rel::Session;


namespace Ucop {
namespace Storage {

	class SQLStorageBase
	{
		template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
	public:
		char const* GetTableName(void) const { return _MytableName; }
		char const* EntryFieldName(void) const { return _MyentryField; }
		FieldFormat GetDstFormat(std::uint32_t _Idx) const { return (FieldFormat)_MydstFormat[_Idx]; }
		const char* GetDstFormat(void) const { return _MydstFormat; }
		FieldFormat GetSrcFormat(std::uint32_t _Idx) const { return (FieldFormat)_MysrcFormat[_Idx]; }
		const char* GetSrcFormat(void) const { return _MysrcFormat; }
		std::uint32_t GetMaxEntry(void) const { return _MymaxEntry; }
		std::uint32_t GetRecordCount(void) const { return _MyrecordCount; }

		template<typename T>
		class SQLSIterator
		{
			friend class SQLStorageBase;
		public:
			T const* GetValue(void) const { return reinterpret_cast<T const*>(_Mypointer); }
			void operator ++(void) { _Mypointer += _MyrecordSize; }
			T const* operator *(void) const { return GetValue(); }
			T const* operator ->(void) const { return GetValue(); }
			bool operator <(const SQLSIterator& _R) const { return _Mypointer < _R._Mypointer; }
			void operator =(const SQLSIterator& _R) { _Mypointer = _R._Mypointer; _MyrecordSize = _R._MyrecordSize; }

		private:
			SQLSIterator(char* _Ptr, std::uint32_t _RecordSize) : _Mypointer(_Ptr), _MyrecordSize(_RecordSize) {}

			char* _Mypointer;
			std::uint32_t _MyrecordSize;
		};

		template<typename T>
		SQLSIterator<T> GetDataBegin(void) const { return SQLSIterator<T>(_Mydata, _MyrecordSize); }

		template<typename T>
		SQLSIterator<T> GetDataEnd(void) const { return SQLSIterator<T>(_Mydata + _MyrecordCount * _MyrecordSize, _MyrecordSize); }

	protected:
		SQLStorageBase(void);
		virtual ~SQLStorageBase(void) { Free(); }

		void Initialize(const char* _TableName, const char* _EntryField, const char* _SrcFormat, const char* _DstFormat);
		std::uint32_t GetDstFieldCount(void) const { return _MydstFieldCount; }
		std::uint32_t GetSrcFieldCount(void) const { return _MysrcFieldCount; }
		std::uint32_t GetRecordSize(void) const { return _MyrecordSize; }

		virtual void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize);
		virtual void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) = 0;
		virtual void Free(void);

	private:
		char* CreateRecord(std::uint32_t _RecordId);

		// Information about the table
		const char* _MytableName;
		const char* _MyentryField;
		const char* _MysrcFormat;
		const char* _MydstFormat;

		// Information about the records
		std::uint32_t _MydstFieldCount;
		std::uint32_t _MysrcFieldCount;
		std::uint32_t _MyrecordCount;
		std::uint32_t _MymaxEntry;
		std::uint32_t _MyrecordSize;

		// Data Storage
		char* _Mydata;
	};


	class SQLStorage : public SQLStorageBase
	{
		template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;

	public:
		SQLStorage(const char* _Fmt, const char* _EntryField, const char* _SqlName);
		SQLStorage(const char* _SrcFmt, const char* _DstFmt, const char* _EntryField, const char* _SqlName);
		~SQLStorage(void) { Free(); }

		template<class T>
		T const* LookupEntry(std::uint32_t _ID) const
		{
			if (_ID >= GetMaxEntry()) {
				return NULL;
			}
			return reinterpret_cast<T const*>(_Myindex[_ID]);
		}

		template<typename BarType>
		void Load(Session& _Sess, bool _ErrorAtEmpty = true, void(*_ErrorHandler)(const char*, ...) = NULL)
		{
			SQLStorageLoader loader;
			loader.Load<BarType>(_Sess, *this, _ErrorAtEmpty, _ErrorHandler);
		}
		void EraseEntry(std::uint32_t _ID);

	protected:
		void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize) override;
		void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) override
		{
			_Myindex[_RecordId] = _Record;
		}
		void Free(void) override;

	private:
		char** _Myindex; /**< Lookup access */
	};


	class SQLHashStorage : public SQLStorageBase
	{
		template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;

	public:
		SQLHashStorage(const char* _Fmt, const char* _EntryField, const char* _SqlName);
		SQLHashStorage(const char* _SrcFmt, const char* _DstFmt, const char* _EntryField, const char* _SqlName);
		~SQLHashStorage(void) { Free(); }

		template<class T>
		T const* LookupEntry(std::uint32_t _ID) const
		{
			RecordMap::const_iterator _Find = _MyindexMap.find(_ID);
			if (_Find != _MyindexMap.end()) {
				return reinterpret_cast<T const*>(_Find->second);
			}
			return NULL;
		}

		template<typename BarType>
		void Load(Session& _Sess, bool _ErrorAtEmpty = true, void(*_ErrorHandler)(const char*, ...) = NULL)
		{
			SQLHashStorageLoader loader;
			loader.Load<BarType>(_Sess, *this, _ErrorAtEmpty, _ErrorHandler);
		}
		void EraseEntry(std::uint32_t _ID);

	protected:
		void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize) override;
		void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) override
		{
			_MyindexMap[_RecordId] = _Record;
		}

		void Free() override;

	private:
		typedef boost::unordered_map< std::uint32_t /*recordId*/, char* /*record*/ > RecordMap;
		RecordMap _MyindexMap; /**< TODO */
	};


	class SQLMultiStorage : public SQLStorageBase
	{
		template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
		template<typename T> friend class SQLMultiSIterator;
		template<typename T> friend class SQLMSIteratorBounds;

	private:
		typedef std::multimap < std::uint32_t /*recordId*/, char* /*record*/ > RecordMultiMap;

	public:
		SQLMultiStorage(const char* _Fmt, const char* _EntryField, const char* _SqlName);
		SQLMultiStorage(const char* _SrcFmt, const char* _DstFmt, const char* _EntryField, const char* _SqlName);
		~SQLMultiStorage(void) { Free(); }

		// forward declaration
		template<typename T> class SQLMSIteratorBounds;

		template<typename T>
		class SQLMultiSIterator
		{
			friend class SQLMultiStorage;
			friend class SQLMSIteratorBounds < T > ;

		public:
			T const* GetValue() const { return reinterpret_cast<T const*>(_MycIterator->second); }
			std::uint32_t GetKey() const { return _MycIterator->first; }
			void operator ++() { ++_MycIterator; }
			T const* operator *() const { return GetValue(); }
			T const* operator ->() const { return GetValue(); }
			bool operator !=(const SQLMultiSIterator& _R) const { return _MycIterator != _R._MycIterator; }
			bool operator ==(const SQLMultiSIterator& _R) const { return _MycIterator == _R._MycIterator; }

		private:
			SQLMultiSIterator(RecordMultiMap::const_iterator _Itr) : _MycIterator(_Itr) {}

			RecordMultiMap::const_iterator _MycIterator; /**< TODO */
		};

		template<typename T>
		class SQLMSIteratorBounds
		{
			friend class SQLMultiStorage;

		public:
			const SQLMultiSIterator<T> first;
			const SQLMultiSIterator<T> second;

		private:
			SQLMSIteratorBounds(std::pair<RecordMultiMap::const_iterator, RecordMultiMap::const_iterator> _Pair) : first(_Pair.first), second(_Pair.second) {}
		};

		template<typename T>
		SQLMSIteratorBounds<T> GetBounds(std::uint32_t _Key) const { return SQLMSIteratorBounds<T>(_MyindexMultiMap.equal_range(_Key)); }


		template<typename BarType>
		void Load(Session& _Sess, bool _ErrorAtEmpty = true, void(*_ErrorHandler)(const char*, ...) = NULL)
		{
			SQLMultiStorageLoader loader;
			loader.Load<BarType>(_Sess, *this, _ErrorAtEmpty, _ErrorHandler);
		}
		void EraseEntry(std::uint32_t _ID);

	protected:
		void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize) override;
		void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) override
		{
			_MyindexMultiMap.insert(RecordMultiMap::value_type(_RecordId, _Record));
		}
		void Free(void) override;

	private:
		RecordMultiMap _MyindexMultiMap;
	};


	///////////////////////////////////////////////////////////////////////////
	/* Loader */

	template <class DerivedLoader, class StorageClass>
	class SQLStorageLoaderBase
	{
	public:
		template<typename BarType>
		bool Load(Session &_Sess, StorageClass& _Storage, bool _ErrorAtEmpty = true, void(*_ErrorHandler)(const char*, ...) = NULL);

		template<class S, class D>
		void convert(std::uint32_t _FieldPos, S _Src, D& _Dst);
		void convert(std::uint32_t _FieldPos, char _Src, bool& _Dst) { _Dst = (_Src != 0); }
		void convert(std::uint32_t _FieldPos, std::uint32_t _Src, bool& _Dst) { _Dst = (_Src != 0); }
		void convert(std::uint32_t _FieldPos, float _Src, bool& _Dst) {
			_Dst = (_Src > 0.0f || _Src < 0.0f);
		}

		template<class S>
		void convert_to_str(std::uint32_t _FieldPos, S _Src, char*& _Dst);

		template<class D>
		void convert_from_str(std::uint32_t _FieldPos, char const* _Src, D& _Dst);

		void convert_str_to_str(std::uint32_t _FieldPos, char const* _Src, char*& _Dst);

		template<class S, class D>
		void default_fill(std::uint32_t _FieldPos, S _Src, D& _Dst);

		void default_fill_to_str(std::uint32_t _FieldPos, char const* _Src, char*& _Dst);

		template<class D>
		void convert_from_str(std::uint32_t _FieldPos, char* _Src, D& _Dst);

		void convert_str_to_str(std::uint32_t _FieldPos, char* _Src, char*& _Dst);

	private:
		template<class V>
		void StoreValue(V _Value, StorageClass& _Store, char* _Record, std::uint32_t _FieldPos, std::uint32_t& _Offset);

		void StoreValue(char const* _Value, StorageClass& _Store, char* _Record, std::uint32_t _FieldPos, std::uint32_t& _Offset);
		void StoreValue(char* _Value, StorageClass& _Store, char* _Record, std::uint32_t _FieldPos, std::uint32_t& _Offset);
	};


	class SQLStorageLoader : public SQLStorageLoaderBase < SQLStorageLoader, SQLStorage >
	{
	};


	class SQLHashStorageLoader : public SQLStorageLoaderBase < SQLHashStorageLoader, SQLHashStorage >
	{
	};

	class SQLMultiStorageLoader : public SQLStorageLoaderBase < SQLMultiStorageLoader, SQLMultiStorage >
	{
	};

}}

#endif /* DEPENDENCY_UCOP_STORAGE_SQLSTORAGE_H_ */
